package server

import (
	"fmt"
	"net"
	"sync"

	"github.com/spf13/cobra"
	"go.uber.org/zap"

	"go-war3proxy/pkg/const"
	pb "go-war3proxy/pkg/proto"
	"go-war3proxy/pkg/utils"
)

// Server War3代理服务器
type Server struct {
	listener  net.Listener
	logger    *zap.Logger
	clientMap map[string]*ClientSession
	ipPool    *IPPool
	mutex     sync.RWMutex
}

// ServerConfig 服务器配置
type ServerConfig struct {
	IP   string
	Port int
}

// NewServer 创建新的服务器实例
func NewServer(config ServerConfig, logger *zap.Logger) *Server {
	return &Server{
		logger:    logger,
		clientMap: make(map[string]*ClientSession),
		ipPool:    NewIPPool(),
	}
}

// Start 启动服务器
func (s *Server) Start(config ServerConfig) error {
	var err error
	address := fmt.Sprintf("%s:%d", config.IP, config.Port)

	s.listener, err = net.Listen("tcp", address)
	if err != nil {
		return fmt.Errorf("监听地址 %s 失败: %w", address, err)
	}

	defer s.listener.Close()

	s.logger.Info("TCP服务器启动成功",
		zap.String("address", address),
		zap.Int("available_ips", s.ipPool.AvailableIPCount()))

	// 主循环，持续接受客户端连接
	for {
		conn, err := s.listener.Accept()
		if err != nil {
			s.logger.Error("接受连接失败", zap.Error(err))
			continue
		}

		go s.handleClient(conn)
	}
}

// handleClient 处理单个客户端连接
func (s *Server) handleClient(conn net.Conn) {
	logger := s.logger.With(zap.String("remote_addr", conn.RemoteAddr().String()))

	// 读取第一个消息来确定客户端意图
	message, err := utils.ReceiveProtobufMessage(conn, logger)
	if err != nil {
		logger.Error("读取初始消息失败", zap.Error(err))
		conn.Close()
		return
	}

	switch message.Type {
	case pb.MessageType_CLIENT_CONNECT:
		s.handleClientConnect(conn, logger)
	case pb.MessageType_WAR3_CONNECT:
		s.handleWar3Connect(message, conn, logger)
	case pb.MessageType_PROVIDE_WAR3:
		s.handleProvideWar3(message, conn, logger)
	default:
		logger.Error("未知的命令", zap.String("type", message.Type.String()))
		conn.Close()
	}
}

// handleClientConnect 处理客户端连接命令，分配IP并注册到clientMap
func (s *Server) handleClientConnect(conn net.Conn, logger *zap.Logger) {
	war3IP := s.ipPool.AcquireIP()

	// 获取其他已连接客户端的IP列表
	var otherIPs []string
	s.mutex.RLock()
	for ip := range s.clientMap {
		otherIPs = append(otherIPs, ip)
	}
	s.mutex.RUnlock()

	logger.Info("分配War3IP",
		zap.String("war3_ip", war3IP),
		zap.Strings("other_ips", otherIPs))

	// 创建IP分配消息
	ipAssignment := &pb.IpAssignment{
		AssignedIp: war3IP,
		OtherIps:   otherIPs,
	}

	message := &pb.War3Message{
		Type:    pb.MessageType_CLIENT_CONNECT_RESULT,
		Payload: &pb.War3Message_IpAssignment{IpAssignment: ipAssignment},
	}

	if err := utils.SendProtobufMessage(conn, message, logger); err != nil {
		logger.Error("发送IP分配消息失败", zap.Error(err))
		s.ipPool.ReleaseIP(war3IP)
		conn.Close()
		return
	}

	// 创建客户端会话
	clientSession := NewClientSession(war3IP, conn, logger)

	s.mutex.Lock()
	s.clientMap[war3IP] = clientSession
	s.mutex.Unlock()

	// 启动客户端会话处理
	go clientSession.Start(s)

	// 通知所有已连接客户端更新列表
	s.notifyAllClientsUpdate()
}

// handleWar3Connect 处理魔兽客户端连接命令，建立数据转发通道
func (s *Server) handleWar3Connect(message *pb.War3Message, conn net.Conn, logger *zap.Logger) {
	dstIP := message.TargetIp

	s.mutex.RLock()
	dstClientSession := s.clientMap[dstIP]
	s.mutex.RUnlock()

	if dstClientSession == nil {
		logger.Error("未找到目标客户端", zap.String("dst_ip", dstIP))
		conn.Close()
		return
	}

	// 通知目标客户端准备连接
	if err := dstClientSession.Notification(); err != nil {
		logger.Error("发送通知失败", zap.Error(err))
		conn.Close()
		return
	}

	// 等待目标客户端提供的连接
	dstConn := dstClientSession.PollQueue()
	if dstConn == nil {
		logger.Error("等待目标连接超时",
			zap.String("dst_ip", dstIP),
			zap.String("dst_client_war3_ip", dstClientSession.GetWar3IP()))
		conn.Close()
		return
	}

	logger.Info("开始数据转发",
		zap.String("src_conn", conn.RemoteAddr().String()),
		zap.String("dst_conn", dstConn.RemoteAddr().String()))

	// 启动双向数据转发
	go utils.TransferData(dstConn, conn, s.logger)
	go utils.TransferData(conn, dstConn, s.logger)
}

// handleProvideWar3 处理魔兽服务端提供连接命令，将连接放入队列
func (s *Server) handleProvideWar3(message *pb.War3Message, conn net.Conn, logger *zap.Logger) {
	srcIP := message.SourceIp

	s.mutex.RLock()
	clientSession := s.clientMap[srcIP]
	s.mutex.RUnlock()

	if clientSession != nil {
		logger.Info("提供War3连接", zap.String("src_ip", srcIP))
		clientSession.PutToQueue(conn)
	} else {
		logger.Error("未找到客户端", zap.String("src_ip", srcIP))
		conn.Close()
	}
}

// notifyAllClientsUpdate 通知所有客户端更新列表
func (s *Server) notifyAllClientsUpdate() {
	s.mutex.RLock()
	clients := make([]*ClientSession, 0, len(s.clientMap))
	for _, client := range s.clientMap {
		clients = append(clients, client)
	}
	s.mutex.RUnlock()

	for _, client := range clients {
		go client.UpdateClientList(s.clientMap)
	}
}

// GetClient 获取客户端会话
func (s *Server) GetClient(war3IP string) *ClientSession {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.clientMap[war3IP]
}

// RemoveClient 移除客户端会话
func (s *Server) RemoveClient(war3IP string) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if _, exists := s.clientMap[war3IP]; exists {
		delete(s.clientMap, war3IP)
		s.logger.Info("移除客户端会话", zap.String("war3_ip", war3IP))
		// 通知其他客户端更新列表
		go s.notifyAllClientsUpdate()
	}
}

// GetClientCount 获取当前连接的客户端数量
func (s *Server) GetClientCount() int {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return len(s.clientMap)
}

// Close 关闭服务器
func (s *Server) Close() error {
	if s.listener != nil {
		return s.listener.Close()
	}
	return nil
}

// NewServerCommand 创建服务器命令
func NewServerCommand(logger *zap.Logger) *cobra.Command {
	var config ServerConfig

	cmd := &cobra.Command{
		Use:   "server",
		Short: "启动War3代理服务器",
		Long:  `启动War3代理服务器，用于协调客户端之间的连接和数据转发`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if config.IP == "" {
				config.IP = consts.DefaultServerIP
			}
			if config.Port == 0 {
				config.Port = consts.DefaultServerPort
			}

			server := NewServer(config, logger)
			return server.Start(config)
		},
	}

	cmd.Flags().StringVarP(&config.IP, "ip", "i", "", "TCP服务器IP地址 (默认: 0.0.0.0)")
	cmd.Flags().IntVarP(&config.Port, "port", "p", 0, "TCP服务器端口 (默认: 9527)")

	return cmd
}
